/* Parser specification  */
/* Your name:    LUONG VINH THAO        */
/* Your id:      PUFMINF1209        */  

%{

%}

/* token declarations */

%token  BOOL BREAK CLASS CONTINUE DO DOWNTO ELSE EXTENDS FLOAT FOR IF INTEGER NEW REPEAT STRING THEN TO UNTIL WHILE
									RETURN VOID  NULL SELF 
									     
%token ADD SUB MUL FDIVI IDIVI MOD
%token EQUAL LESS GREAT LEQUAL GEQUAL NEQUAL AND NOT OR ASSIG ONEQUAL CONCAT
%token LSQUARE RSQUARE LPAREN RPAREN LBRACK RBRACK SEMICOLON COLON DCOLON DOT COMMA
%token<int> INT_LITERAL
%token<string> ID 
%token<string> STRING_LITERAL 
%token<float> FLOAT_LITERAL
%token<bool> BOOL_LITERAL

%token EOF

%nonassoc LESS GREAT LEQUAL GEQUAL  /* lowest precedence */
%nonassoc EQUAL NEQUAL

%left AND, OR
%left ADD,SUB
%left MUL, FDIVI, IDIVI,MOD 

%left CONCAT
%nonassoc NOT

%nonassoc UNARY
%nonassoc LSQUARE COLON RSQUARE
%left DOT
%nonassoc NEW /* highest precedence */
%nonassoc LOWER_ELSE
%nonassoc ELSE
/* Start symbol S's declaration (which symbol of the start symbol) */
%start program /*the entry point*/
%type <unit> program 

%%

/* Rule definitions */

program:
	manyclassdeclaration EOF {  }
	|{}
	
;

manyclassdeclaration: oneclassdecl {}
											| oneclassdecl manyclassdeclaration {}
											| method_declaration manyclassdeclaration {}
											|method_declaration {}
											| attributes manyclassdeclaration {}
											| attributes {}
;
 /*constant-variable declare */
consDeclare: ID ONEQUAL expr  SEMICOLON  {} 
; 

var :idList COLON Type {}
;
varDeclare: var SEMICOLON{}
		
;
idList: ID COMMA idList{}
				|ID {}
;
/*class declare*/
oneclassdecl: CLASS ID LPAREN list_member  RPAREN {}
							|  CLASS ID EXTENDS ID LPAREN  list_member RPAREN {}
;
list_member: 
						|attributes list_member {}
						|method_prototype list_member {}
						| {}
;
attributes:
						|consDeclare {}
						|varDeclare {}
 ;
method_prototype:
						| Type ID  LBRACK list_parameter  RBRACK SEMICOLON {}
						| ID  LBRACK list_parameter  RBRACK SEMICOLON {}
;		  

list_parameter:
						|var SEMICOLON list_parameter  {}
						|var {}
						| {}
;
/*method declare*/
method_declaration:
						| Type ID DCOLON ID LBRACK list_parameter RBRACK LPAREN body RPAREN  {}
						| ID DCOLON ID LBRACK list_parameter RBRACK LPAREN body RPAREN  {}
;
body:
		|	attributes body {}
		| list_stmt {}
		| {}
;
list_stmt:
		| stmt {}
		| stmt list_stmt {}
 ;
/*Type*/
Type: 
			|primiviteType {}
			| arrayType {}
			| classType {}
;

primiviteType :
		| VOID {}
		|elmentType {}
;
arrayType:
		| elmentType LSQUARE INT_LITERAL RSQUARE {} 
		| classType LSQUARE INT_LITERAL RSQUARE {}
;
elmentType :
		| FLOAT {}
		| STRING {}
		| BOOL {}
		| INTEGER {}
		
;
classType:
	| ID{}
 ;
/*expr*/
expr: 
			|ID {}   
			|INT_LITERAL {}
			| FLOAT_LITERAL {}
			| BOOL_LITERAL {}
			| STRING_LITERAL {}
			| SELF{}
			| expr ADD expr {} /* pri expr*/
			| expr SUB expr {}
			| expr MUL expr {}
			| expr FDIVI expr {}
			| expr IDIVI expr {}
			| expr MOD expr {}	 
			| expr AND expr {} /* Bool expr*/
			| expr OR expr {}  		
			| expr  CONCAT  expr {} /* String expr*/
			| expr  EQUAL  expr {} /* relation expr*/
			| expr  NEQUAL  expr  {}   
			| expr GREAT expr {}
			| expr LESS expr {} 
			| expr GEQUAL expr {}
			| expr LEQUAL expr {}
			| ADD expr %prec UNARY {}
			| SUB expr %prec UNARY {} 
			|  NOT expr {}  
			| LBRACK expr RBRACK{} /* relation expr*/			
			| member_access{}
			| NEW classType LBRACK list_argument RBRACK {} /*Object creation */
			| index{}	/*index */
	;		
member_access:
			| SELF DOT ID {} /*member access*/
			| SELF DOT ID LBRACK list_argument RBRACK {} 
			| ID DOT ID LBRACK list_argument RBRACK {}
;
index:
		 | expr LSQUARE expr RSQUARE {}	/*index */
	;
argument:
						|expr {}
						| {}
;
list_argument:
						| argument COMMA  list_argument {}
						| argument {}
				
;

/*part 6 statment* */
stmt:
		|block_stmt  {}
		|assignment_stmt {}
		|if_stmt{}
		|while_stmt{} 
		| repeat_stmt {}
		| for_stmt {}
		| break_stmt{}
		| continue_stmt{}
		| return_stmt {}
		| method_invocate_stmt{}
		
	;
block_stmt:
	| LPAREN body RPAREN{}
	;
/*assign*/
assignment_stmt :
		| lhs ASSIG expr SEMICOLON {}
		
	;						
lhs:
		|ID{}
		| index{}
		| member_access{}

	;
/*if statment*/
if_stmt:
		| IF expr THEN stmt {}  %prec LOWER_ELSE
		| IF expr THEN stmt ELSE stmt {}
;
/*while statment conflit*/
while_stmt:
		| WHILE expr DO stmt {}
	 ;
/*repeat statment*/
repeat_stmt:
		|REPEAT list_stmt UNTIL expr SEMICOLON {}
;
continue_stmt:
		|CONTINUE SEMICOLON{}
;
for_stmt:
		| FOR ID ASSIG expr TO expr DO LPAREN list_stmt RPAREN {}
		|  FOR ID ASSIG expr DOWNTO expr DO LPAREN list_stmt RPAREN {}
;
break_stmt:
		|BREAK SEMICOLON {}
 ;
return_stmt:
		| RETURN expr SEMICOLON {}
	;
method_invocate_stmt:
		|ID DOT ID LBRACK list_argument RBRACK SEMICOLON {}
		| SELF DOT ID LBRACK list_argument RBRACK SEMICOLON {}
	
;

